﻿using System;
using System.Linq;
using System.Text;

namespace Centido.Core
{
    /// <summary>
    ///   A set of table read all where operations.
    /// </summary>
    public static class TableReadAllWhereOperations
    {
        /// <summary>
        ///   Reads all rows where the specified column contains the specified value
        /// in the specified data source.
        /// </summary>
        /// <param name="table">The target table.</param>
        /// <param name="source">The target data source.</param>
        /// <param name="whereColumn">The filter column value.</param>
        /// <param name="readAction">The read action to be performed upon each result row.</param>
        /// <param name="values">The list of table column to be read.</param>
        private static void ReadAllRowsWhereImplementation(Table table,
            DataSource source, ColumnValue whereColumn,
            Action readAction, params ColumnValue[] values)
        {
            if (whereColumn == null)
                throw new ArgumentNullException("whereColumn");

            // If there is nothing to read
            if (values == null || values.Length == 0)
                throw new ArgumentException("No table columns to be read were specified.");

            var tableName = table.GetDataSourceName(source);

            // List of comma separated column names
            var columnList = new StringBuilder();

            values.ToList().ForEach(
                pair => columnList.Append(columnList.Length != 0 ? "," : string.Empty).Append(pair.ColumnName));

            table.Domain.DbAccess.ExecuteReader(
                cmd =>
                {
                    cmd.CommandText = string.Format(
                        "select {0} from {1} where {2}=?",
                        columnList,
                        tableName,
                        whereColumn.ColumnName);

                    cmd.Parameters.Add(table.Domain.DbAccess.CreateParameter("where_value",
                        whereColumn.Column.ValueOdbcType, whereColumn.Value));
                },
                reader =>
                {
                    foreach (var value in values.ToList())
                        value.Value = reader[value.ColumnName];

                    if (readAction != null)
                        readAction();
                });
        }


        /// <summary>
        ///   Reads all rows where the target column contains the specified value.
        /// </summary>
        /// <remarks>
        /// <para>The current user has to have the select permission on the table in order
        /// to execute this function.</para>
        /// </remarks>
        /// <param name="table">The target table.</param>
        /// <param name="whereColumn">The filter column value.</param>
        /// <param name="readAction">The read action to be performed upon each result row.</param>
        /// <param name="values">The list of table column to be read.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="whereColumn"/> is null.</exception>
        /// <exception cref="System.ArgumentNullException">Thrown when one of the specified values of the table columns is null.</exception>
        /// <exception cref="ArgumentException">Thrown when no table columns were specified.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to read from the table.</exception>
        /// <example>
        ///   The following example shows how to read all rows where the target column contains the specified value.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a new table
        ///             var table = domain.AddTable("students");
        /// 
        ///             //Creating a surname column
        ///             var surnameColumn = table.AddColumn("surname", ColumnType.String);
        /// 
        ///             //Creating an age column
        ///             var ageColumn = table.AddColumn("age", ColumnType.Integer);
        /// 
        ///             //Granting all necessary permissions
        ///             table.GrantAll();
        /// 
        ///             table.InsertRow(surnameColumn.Value("Smith"), ageColumn.Value(20));
        ///             table.InsertRow(surnameColumn.Value("Brown"), ageColumn.Value(20));
        ///             table.InsertRow(surnameColumn.Value("Anderson"), ageColumn.Value(21));
        /// 
        ///             //Reading all rows where the age is 20
        ///             var surname = surnameColumn.EmptyValue();
        /// 
        ///             table.ReadAllRowsWhere(ageColumn.Value(20), () =&gt;
        ///             {
        ///                 Console.WriteLine("Student of 20: surname = {0}", surname.GetString());
        ///             }, surname); 
        ///         }
        ///     }
        /// </code>
        /// </example>
        public static void ReadAllRowsWhere(this Table table, ColumnValue whereColumn,
            Action readAction, params ColumnValue[] values)
        {
            if (table == null)
                throw new ArgumentNullException("table");
            if (whereColumn == null)
                throw new ArgumentNullException("whereColumn");

            ReadAllRowsWhereImplementation(table, DataSource.UserView, whereColumn, readAction, values);
        }


        /// <summary>
        ///   Reads all rows where the target column contains the specified value
        /// in the specified data source.
        /// </summary>
        /// <remarks>
        /// <para>The current user has to have the select permission on the table in order
        /// to execute this function.</para>
        /// </remarks>
        /// <param name="table">The target table.</param>
        /// <param name="source">The target data source.</param>
        /// <param name="whereColumn">The filter column value.</param>
        /// <param name="readAction">The read action to be performed upon each result row.</param>
        /// <param name="values">The list of table column to be read.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="whereColumn"/> is null.</exception>
        /// <exception cref="System.ArgumentNullException">Thrown when one of the specified values of the table columns is null.</exception>
        /// <exception cref="ArgumentException">Thrown when no table columns were specified.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to read from the table.</exception>
        /// <example>
        ///   The following example shows how to read all rows where the target column contains the specified value.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a new table
        ///             var table = domain.AddTable("students");
        /// 
        ///             //Creating a surname column
        ///             var surnameColumn = table.AddColumn("surname", ColumnType.String);
        /// 
        ///             //Creating an age column
        ///             var ageColumn = table.AddColumn("age", ColumnType.Integer);
        /// 
        ///             //Granting all necessary permissions
        ///             table.GrantAll();
        /// 
        ///             table.InsertRow(surnameColumn.Value("Smith"), ageColumn.Value(20));
        ///             table.InsertRow(surnameColumn.Value("Brown"), ageColumn.Value(20));
        ///             table.InsertRow(surnameColumn.Value("Anderson"), ageColumn.Value(21));
        /// 
        ///             //Reading all rows where the age is 20
        ///             var surname = surnameColumn.EmptyValue();
        /// 
        ///             table.ReadAllRowsWhere(DataSource.UserView, ageColumn.Value(20), () =&gt;
        ///             {
        ///                 Console.WriteLine("Student of 20: surname = {0}", surname.GetString());
        ///             }, surname); 
        ///         }
        ///     }
        /// </code>
        /// </example>
        public static void ReadAllRowsWhere(this Table table,
            DataSource source, ColumnValue whereColumn, Action readAction,
            params ColumnValue[] values)
        {
            ReadAllRowsWhereImplementation(table, source, whereColumn, readAction, values);
        }
    }
}
